package com.java.synchronized_;

/**
 * 同步代码块解决线程安全问题
 */
public class SynchronizedCodeBlock {
    static class ThreadSon extends Thread {
        // static修饰是因为票的数量应该被所有窗口共享
        static int ticket = 0;
        
        // synchronized的锁对象相当于钥匙
        static Object key1 = new Object(); // static修饰是因为该对象应该被所有窗口共享，即钥匙是同一把
        Class key2 = ThreadSon.class; // 每个类在内存中存在唯一一个Class实例，即钥匙是同一把(常用)
        
        ThreadSon noKey = this; // 每个对象的this都不同，钥匙改为this则仍然出现重复卖或卖超的问题，即钥匙不是同一把
        
        @Override
        public void run() {
            while (true) { // while不能在同步代码块内部，否则票将由同一窗口卖
                synchronized (key1) { // 同步代码块⭐⭐⭐
                    if (ticket > 9) {
                        break;
                    }
                    
                    try {
                        Thread.sleep(10); // 模拟窗口出票延时
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    ticket++;
                    System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
                }
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        new ThreadSon().start();
        new ThreadSon().start();
        new ThreadSon().start();
    }
    
    /**
     * 输出结果如下，每次运行的结果不同！未出现重复卖或卖超的问题
     * Thread-0正在卖第1张票
     * Thread-2正在卖第2张票
     * Thread-1正在卖第3张票
     * Thread-1正在卖第4张票
     * Thread-0正在卖第5张票
     * Thread-2正在卖第6张票
     * Thread-2正在卖第7张票
     * Thread-0正在卖第8张票
     * Thread-1正在卖第9张票
     * Thread-0正在卖第10张票
     */
}
